home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / gus / guspeak.zip / SPEAK.C < prev    next >
C/C++ Source or Header  |  1993-06-24  |  8KB  |  345 lines

  1. /************************************************************************
  2. *                                    *
  3. *   Copyright 1990, Brown University, Providence, RI.            *
  4. *   Permission to use, copy, modify and distribute this software and    *
  5. *   its documentation for any purpose other than its incorporation    *
  6. *   into a commercial product, is hereby granted, provided that this    *
  7. *   copyright notice appears on all copies.                *
  8. *                                    *
  9. ************************************************************************/
  10. /************************************************************************
  11. *                                    *
  12. *    speak.c                                *
  13. *                                    *
  14. ************************************************************************/
  15. #include <sys/types.h>
  16. #include <time.h>
  17. #include <sys/stat.h>
  18. /*#include <multimedia/libaudio.h> */
  19. #include <dirent.h>
  20. #include <fcntl.h>
  21. #include <errno.h>
  22. #include <stdio.h>
  23.  
  24. /************************************************************************
  25. *                                    *
  26. *    type and array of phoneme audio samples                *
  27. *                                    *
  28. ************************************************************************/
  29. typedef struct phoneme_t {
  30.     int size;
  31.     char *data;
  32. };
  33.  
  34. static struct phoneme_t phoneme[1024];
  35.  
  36. /************************************************************************
  37. *                                    *
  38. *    names of known phonemes                        *
  39. *                                    *
  40. ************************************************************************/
  41. static
  42. char *phoneme_name[] = {
  43.     "IY",    "EY",    "AE",    "AO",    "UH",
  44.     "ER",    "AH",    "AW",    "IH",    "EH",
  45.     "AA",    "OW",    "UW",    "AX",    "AY",
  46.     "OY",    "YU",    "p",    "t",    "k",    "f",
  47.     "TH",    "s",    "SH",    "HH",    "n",
  48.     "l",    "y",    "CH",    "WH",    "b",
  49.     "d",    "g",    "v",    "DH",    "z",
  50.     "ZH",    "m",    "NG",    "w",    "r",    "j",
  51.     (char *)0
  52. };
  53.  
  54. extern FILE *In_file;        /* from parse.c */
  55. extern char *sys_errlist[];
  56.  
  57. static char *buffer;
  58. static int curfd;
  59.  
  60. speak_load_samples(dir)
  61.    char *dir;
  62. {
  63.    register i, k, rv;
  64.    char *cp;
  65.    int fd;
  66.    int first = 1;
  67.    char cwd[1024];
  68.    DIR *dirp;
  69.    struct dirent *dp;
  70.    struct stat st;
  71.    Audio_hdr ah, sah;
  72.  
  73.    if ((dirp = opendir(dir)) == 0)
  74.       return fatal(0, "can't open directory %s", dir);
  75.  
  76.    (void) getwd(cwd);
  77.    if (chdir(dir))
  78.       return fatal(AUDIO_UNIXERROR, dir);
  79.  
  80.    while (dp = readdir(dirp)) {
  81.       for (    cp=phoneme_name[i=0];
  82.         cp && strcmp(dp->d_name, cp)!=0;
  83.         cp=phoneme_name[++i]);
  84.       if (cp == (char *)0)
  85.          continue;
  86.  
  87.       if ((fd = open(dp->d_name, O_RDONLY)) < 0)
  88.          return fatal(AUDIO_UNIXERROR, dp->d_name);
  89.       if ((rv = audio_read_filehdr(fd, &ah, 0, 0)) != AUDIO_SUCCESS)
  90.          return fatal(rv, dp->d_name);
  91.       if (first) {
  92.          bcopy(&ah, &sah);
  93.          first = 0;
  94.       }
  95. /*
  96.       else if (audio_cmp_hdr(&ah, &sah))
  97.          return fatal(0, "phoneme audio headers don't match");
  98. */
  99.  
  100.       i = ch_to_code(&cp);
  101.       if (phoneme[i].data)
  102.          free(phoneme[i].data);
  103.  
  104.       if (ah.data_size == AUDIO_UNKNOWN_SIZE) {        /* pffft */
  105.          if (fstat(fd, &st))
  106.             return fatal(AUDIO_UNIXERROR, dp->d_name);
  107.          phoneme[i].size = st.st_size;
  108.       }
  109.       else
  110.          phoneme[i].size = ah.data_size;
  111.  
  112.       if ((phoneme[i].data = (char *)malloc(phoneme[i].size)) == 0)
  113.          return fatal(0, "malloc returned zero");
  114.  
  115.       if ((rv = read(fd, phoneme[i].data, phoneme[i].size)) <= 0)
  116.          return fatal(AUDIO_UNIXERROR, dp->d_name);
  117.  
  118.       if (rv < phoneme[i].size)
  119.          phoneme[i].size = rv;
  120.  
  121.       close(fd);
  122.    }
  123.    closedir(dirp);
  124.  
  125.    for (cp=phoneme_name[i=0]; cp; cp=phoneme_name[++i]) {
  126.       k = ch_to_code(&cp);
  127.       if (phoneme[k].size == 0)
  128.          return fatal(0, "zero length phoneme '%s'", phoneme_name[i]);
  129.    }
  130.  
  131.    if (chdir(cwd))
  132.       return fatal(AUDIO_UNIXERROR, cwd);
  133.  
  134.    return 0;
  135. }
  136.  
  137. int
  138. speak_open(device, now)
  139.    char *device;
  140.    int now;
  141. {
  142.    int fd;
  143.    struct stat st;
  144.  
  145.    if (device == 0)
  146.       device = "/dev/audio";
  147.  
  148.    if (stat(device, &st))
  149.       return fatal(AUDIO_UNIXERROR, device);
  150.  
  151.    if (!S_ISCHR(st.st_mode))
  152.       return fatal(0, "%s is not an audio device", device);
  153.  
  154.    if ((fd = open(device, O_WRONLY | (now? O_NDELAY:0) )) < 0)
  155.       if (errno == EBUSY)
  156.          return 1;
  157.       else
  158.          return fatal(AUDIO_UNIXERROR, device);
  159.  
  160.    return fd;
  161. }
  162.  
  163. speak_string(fd, str)
  164.    int fd;
  165.    char *str;
  166. {
  167.    buffer = str;
  168.    curfd = fd;
  169.    xlate_file();    /* hook into eng_to_phoneme code */
  170.    buffer = (char *)0;
  171.  
  172.    return 0;
  173. }
  174.  
  175. speak_file(fd, filename)
  176.    int fd;
  177.    char *filename;
  178. {
  179.    if ((In_file = fopen(filename, "r")) == 0)
  180.       return fatal(0, "can't open %s", filename);
  181.  
  182.    xlate_file();
  183.    fclose(In_file);
  184.    In_file = (FILE *)0;
  185.  
  186.    return 0;
  187. }
  188.  
  189. speak_volume(fd, vol)
  190.    int fd;
  191.    double vol;
  192. {
  193. #ifdef DOCUMENTED_BUT_NOT_IN_LIBAUDIO__SIGH
  194.    audio_set_play_gain(fd, &vol);
  195. #endif
  196. }
  197.  
  198. speak_close(fd)
  199.    int fd;
  200. {
  201.    close(fd);
  202.  
  203.    return 0;
  204. }
  205.  
  206. hacked_getc(fp)
  207.    FILE *fp;
  208. {
  209.    static ix;
  210.  
  211.    if (In_file)
  212.       return getc(fp);
  213.  
  214.    if (buffer[ix] == 0) {
  215.       ix = 0;
  216.       return EOF;
  217.    }
  218.    else
  219.       return buffer[ix++];
  220. }
  221.  
  222. phoneme_str_to_audio(cp)
  223.    char *cp;
  224. {
  225.    register i;
  226.  
  227.    while (*cp)
  228.       if (isspace(*cp)) {
  229.          cp++;
  230.          speak_delay(0);
  231.       }
  232.       else {
  233.          i = ch_to_code(&cp);
  234.          write(curfd, phoneme[i].data, phoneme[i].size);
  235.       }
  236. }
  237.  
  238. /************************************************************************
  239. *                                    *
  240. *    ch_to_code                            *
  241. *    code_to_ch                            *
  242. *                                    *
  243. *    Map a phoneme name to a unique index between 1 and 1023, or    *
  244. *    vice versa.  Ch_to_code advances it's argument to the next    *
  245. *    phoneme (or null).  Code_to_ch returns a null-terminated    *
  246. *    string.                                *
  247. *                                    *
  248. ************************************************************************/
  249. int
  250. ch_to_code(cp)
  251.    char **cp;
  252. {
  253.    register char *tp = *cp;
  254.  
  255.    if (islower(*tp)) {
  256.       *cp += 1;
  257.       return *tp - 'a' + 1;
  258.    }
  259.    else {
  260.       *cp += 2;
  261.       return ((*tp - 'A' + 1) << 5) | (*(tp+1) - 'A' + 1);
  262.    }
  263. }
  264.  
  265. char *
  266. code_to_ch(code)
  267.    int code;
  268. {
  269.    static char ch[3];
  270.  
  271.    if (code < (1<<5)) {
  272.       ch[1] = code + 'a' - 1;
  273.       return &ch[1];
  274.    }
  275.    else {
  276.       ch[0] = (code >> 5) + 'A' - 1;
  277.       ch[1] = (code & 0x1f) + 'A' - 1;
  278.       return &ch[0];
  279.    }
  280. }
  281.  
  282. /************************************************************************
  283. *                                    *
  284. *    speak_delay                            *
  285. *                                    *
  286. *    Flush the audio device and pause for the given interval.    *
  287. *    If no interval is specified, pause for 2/10 second.        *
  288. *                                    *
  289. ************************************************************************/
  290. speak_delay(delay)
  291.    int delay;        /* in 10ths of a second */
  292. {
  293.    static struct timeval tv = {0, 200000};    /* 1sec == 1000000 usec */
  294.  
  295.    if (delay)
  296.       tv.tv_usec = delay * 100000;
  297.    (void) audio_drain(curfd, FALSE);
  298.    (void) select(0, 0, 0, 0, &tv);
  299.  
  300.    return 0;
  301. }
  302.  
  303. int
  304. fatal(code, str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  305.    int code;
  306.    char *str;
  307.    int a1, a2, a3, a4, a5, a6, a7, a8, a9;
  308. {
  309.    char *bp;
  310.    char b1[256], b2[256];
  311.  
  312.    bp = (char *)sprintf(b1, str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  313.    if (code)
  314.       switch (code) {
  315.          case AUDIO_UNIXERROR:
  316.             bp = (char *)sprintf(b2, "%s: %s", str, sys_errlist[errno]);
  317.             break;
  318.          case AUDIO_ERR_BADHDR:
  319.             bp = (char *)sprintf(b2, "%s: bad audio header", str);
  320.             break;
  321.          case AUDIO_ERR_BADFILEHDR:
  322.             bp = (char *)sprintf(b2, "%s: bad file header", str);
  323.             break;
  324.          case AUDIO_ERR_BADARG:
  325.             bp = (char *)sprintf(b2, "%s: bad subroutine argument", str);
  326.             break;
  327.          case AUDIO_ERR_NOEFFECT:
  328.             bp = (char *)sprintf(b2, "%s: device control ingnored", str);
  329.             break;
  330.          case AUDIO_ERR_ENCODING:
  331.             bp = (char *)sprintf(b2, "%s: unknown encoding format", str);
  332.             break;
  333.          case AUDIO_ERR_INTERRUPTED:
  334.             bp = (char *)sprintf(b2, "%s: operation was interrupted", str);
  335.             break;
  336.          default:
  337.             bp = (char *)sprintf(b2, "%s: <unknown error code>", str);
  338.             break;
  339.       }
  340.  
  341.    fprintf(stderr, "%s\n", bp);
  342.  
  343.    return -1;
  344. }
  345.